<?php 
Yii::import('application.components.dao.class.DataSourceMapper');
class Dao extends CFormModel{
    protected $_attributesMapper = array();
    protected $_sourceMappers = array();
    protected $_transaction = null;
    
    public function __construct($scenario = ''){
        $this->attributeNames();
        parent::__construct($scenario);
    }
    
    public function init(){}

    public function dataSource(){
        return array();
    }
    
    public function dataSourceRelations(){
        return array();
    }
    
    public function sourceConfig($name){
        $dataSource = $this->dataSource();
        return $dataSource[$name];
    }
    
    public function sources(){
        $sourceList = array();
        $dataSource = $this->dataSource();
        foreach ($dataSource as $sourceName => $sourceConfig){
            $sourceList[$sourceName] = $this->source($sourceName);
        }
        return $sourceList;
    }
    
    public function source($name){
        if (!array_key_exists($name,$this->_sourceMappers)){
            $config = $this->sourceConfig($name);
            $dataMapper = new DataSourceMapper();
            $dataMapper->soruceName = $name;
            $dataMapper->setConfig($config);
            $this->addAttributesMapper($dataMapper->getAttributesMapper());
            $this->_sourceMappers[$name] = $dataMapper;
        }
        return $this->_sourceMappers[$name];
    }
    
    public function attributesMapper(){
        return $this->_attributesMapper;
    }
    
    public function addAttributesMapper($mapper){
        $this->_attributesMapper = array_merge($mapper,$this->_attributesMapper);
        return $this;
    }
    
    public function attributeNames(){
        $attributeNames = parent::attributeNames();
        foreach ($this->sources() as $source){
            $attributeNames = array_merge($source->attributeNames(),$attributeNames);
        }
        return $attributeNames;
    }
    
    protected function getRules(){
        $rules = $this->rules();
        foreach ($this->sources() as $source){
            $rules = array_merge($source->rules(),$rules);
        };
        return $rules;
    }
    
    public function __get($name){
        $attributesMapper = $this->attributesMapper();
        if (array_key_exists($name,$attributesMapper)){
            $tempMapper = explode('.',$attributesMapper[$name]);
            $attributesName = $tempMapper[1];   
            return $this->source($tempMapper[0])->getAttribute($attributesName);
        }
        return parent::__get($name);
    }
    
    public function __set($name, $value){
        $attributesMapper = $this->attributesMapper();
        if (array_key_exists($name,$attributesMapper)){
            $tempMapper = explode('.', $attributesMapper[$name]);
            $attributesName = $tempMapper[1];
            return $this->source($tempMapper[0])->setAttribute($attributesName,$value);
        }
        return parent::__set($name, $value);
    }

    public function createValidators()
    {
        $validators=new CList;
        foreach($this->getRules() as $rule)
        {
            if(isset($rule[0],$rule[1]))  // attributes, validator name
                $validators->add(CValidator::createValidator($rule[1],$this,$rule[0],array_slice($rule,2)));
            else
                throw new CException(Yii::t('yii','{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.',
                    array('{class}'=>get_class($this))));
        }
    
        return $validators;
    }
    
    public function find($id = null){
        if ($id !== null){
            $this->id = $id;
        }
        $findResult = array();
        $dataSourceRelations = $this->dataSourceRelations();

        foreach ($dataSourceRelations as $sourceName => $relations){
            $result = $this->source($sourceName)->findByPk($this->id);
            if (!empty($result)){
                $this->attributes = $result;
                foreach ($relations as $relationSource => $relation){
                    switch ($relation[0]){
                        case 'part':
                            $join = $relation['join'];
                            $masterAttr = key($join);
                            $relationAttr = $join[$masterAttr];
                            $findAttributes = array(
                                $relationAttr => $this->$masterAttr
                            );
                            $this->source($relationSource)->setAttribute($relationAttr,$this->$masterAttr);
                            $relationResult = $this->source($relationSource)->findByAttributes($findAttributes);
                            if (!empty($relationResult)){
                                $this->attributes = $relationResult;
                            }
                            break;
                    }
                }
            }
        }
        return $this;
    }
    
    public function save($runValidation=true,$attributes=null){
        if(!$runValidation || $this->validate($attributes)){

            $saveFlag = true;
            
            $this->_transaction = Yii::app()->db->getCurrentTransaction();
            if ($this->_transaction === null){

                $this->_transaction = Yii::app()->db->beginTransaction();
            }            
            try {
                $dataSourceRelations = $this->dataSourceRelations();
                foreach ($dataSourceRelations as $sourceName => $relations){

                    $save = $this->source($sourceName)->save();
                    
                    if (!empty($save)){
                        foreach ($relations as $relationSource => $relation){
                            switch ($relation[0]){
                                case 'part':
                                    $join = $relation['join'];
                                    $masterAttr = key($join);
                                    $relationAttr = $join[$masterAttr];
                                    $this->source($relationSource)->setAttribute($relationAttr,$this->$masterAttr);
                                    $this->source($relationSource)->save();
                                    break;
                            }
                        }
                    }
                }
                $this->_transaction->commit();
                $saveFlag = true;
            }catch (Exception $e){
                var_dump($e->getMessage());
                $this->_transaction->rollback();
                $saveFlag = false;
            }
            return $saveFlag;
        }else{
            return false;
        }
    }

    public function setScenario($value){
        foreach ($this->sources() as $source){
            $source->getMapper()->setScenario($value);
        }
        return parent::setScenario($value);
    }
    
    /*
    protected function build(){
        $sourceList = $this->dataSource();
        foreach ($sourceList as $name => $source){
            $sourceMap = new DataSourceMap();
            $sourceMap->name = $name;
            $sourceMap->setSource($source);
            $this->_attributesMapper = array_merge($this->_attributesMapper,$sourceMap->attributesMap());            
            $this->_rulesMap = array_merge($this->_rulesMap,$sourceMap->rulesMap());
            $this->_sourceMap[$sourceMap->name] = $sourceMap;
        }  
        $dataSourceRelations = $this->dataSourceRelations();
        foreach ($dataSourceRelations as $sourceName => $dataSourceRelation){
            foreach ($dataSourceRelation as $relationSoruce => $relation){
                $this->source($sourceName)->addRelation($this->source($relationSoruce),$relation[0],$relation);
            }
            
        }
        $this->_findMap = $dataSourceRelations;
        $this->_saveMap = $dataSourceRelations;
        
    }
   
    public function find($id = null){
        if ($id !== null){
            $this->id = $id;
        }
        $findResult = array();
        foreach ($this->_findMap as $sourceName => $map){
            $result = $this->source($sourceName)->dto()->findByPk($this->id);
            if (!empty($result)){
                $this->source($sourceName)->setDto($result);
                $attributes = array_intersect_key($result->attributes,array_flip($this->source($sourceName)->attributes));
                $findResult = array_merge($findResult,$attributes);
               
                $relations = $this->source($sourceName)->relations();
                if (!empty($relations)){
                    foreach ($relations as $relation){
                        $config = $relation->relationsConfig;
                        $join = $relation->relationsConfig['join'];
                        $relationPk = array_values($join);
                        $mastPk = array_keys($join);
                        switch ($config[0]){
                            case 'part':
                                $id = $this->source($sourceName)->dto()->id;
                                $result = $relation->dto()->findByPk($id);
                                if (!empty($result)){
                                    $attributes = array_intersect_key($result->attributes,array_flip($this->source($sourceName)->attributes));
                                    $findResult = array_merge($findResult,$attributes);
                                }
                            break;
                        }
                    }
                }
            }
        
        }
        $this->attributes = $findResult;
    
    }
    
    public function save($runValidation=true,$attributes=null){
        if(!$runValidation || $this->validate($attributes)){
            $saveFlag = true;
            try {
                $transaction = Yii::app()->db->beginTransaction();
    
                foreach ($this->_saveMap as $sourceName => $map){
                    $save = $this->source($sourceName)->dto()->save();
                    if ($save){
                        $relations = $this->source($sourceName)->relations();
                        if (!empty($relations)){
                            foreach ($relations as $relation){
                                $config = $relation->relationsConfig;
                                $join = $relation->relationsConfig['join'];
                                $relationPk = array_values($join);
                                $mastPk = array_keys($join);
                                switch ($config[0]){
                                    case 'part':
                                        $id = $this->source($sourceName)->dto()->id;
                                        $relation->setAttribute($relationPk[0],$id);
                                        $relation->dto()->save();
                                        break;
                                }
                            }
                        }
                    }
                }
    
                $transaction->commit();
                $saveFlag = true;
            }catch (Exception $e){
                var_dump($e->getMessage());
                $transaction->rollback();
                $saveFlag = false;
            }
            return $saveFlag;
        }else{
            return false;
        }
    }
    
  
    
   */
}